package com.beone.admin.security.filter;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.vote.AbstractAccessDecisionManager;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.List;

/**
 * @title  Spring Security 鉴权管理器
 * @Author 覃球球
 * @Version 1.0 on 2017/12/20.
 * @Copyright 长笛龙吟
 */
public class MyAccessDecisionManager extends AbstractAccessDecisionManager {

    private Logger logger = LoggerFactory.getLogger(MyAccessDecisionManager.class);

    public MyAccessDecisionManager(List<AccessDecisionVoter<? extends Object>> decisionVoters) {
        super(decisionVoters);
    }

    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {
        if(configAttributes == null){
            throw new AccessDeniedException("没有权限,拒绝访问!");
        }

//        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
//        logger.info("decide authentication  url : {}", request.getRequestURL());

        //获取当前用户的授权URLs
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        for (ConfigAttribute attribute : configAttributes) {
            if (!(attribute instanceof UrlConfigAttribute)) {
                continue;
            }

            UrlConfigAttribute urlConfigAttribute = (UrlConfigAttribute) attribute;
            for (GrantedAuthority authority : authorities) {
                if (!(authority instanceof PermissionsGrantedAuthority)){
                    continue;
                }
                PermissionsGrantedAuthority grantedAuthority = (PermissionsGrantedAuthority) authority;
                if (StringUtils.isBlank(grantedAuthority.getUrl())){
                    continue;
                }

                if (matchers(grantedAuthority.getUrl(),urlConfigAttribute.getHttpServletRequest())){
                    return;
                }
            }
        }
        throw new AccessDeniedException("没有权限,拒绝访问!");
    }

    /**
     * 用Spring已经实现的AntPathRequestMatcher进行匹配，这样我们数据库中的url也就支持ant风格的配置了（例如：/xxx/user/**）
     * @param url
     * @param request
     * @return
     */
    private boolean matchers(String url, HttpServletRequest request) {
        AntPathRequestMatcher matcher = new AntPathRequestMatcher(url);
        if (matcher.matches(request)) {
            return true;
        }
        return false;
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return false;
    }

    /**
     * Iterates through all <code>AccessDecisionVoter</code>s and ensures each can support
     * the presented class.
     * <p>
     * If one or more voters cannot support the presented class, <code>false</code> is
     * returned.
     *
     * @param clazz the type of secured object being presented
     * @return true if this type is supported
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}
